﻿using System;
using System.Globalization;
using MockCommon;
using MockDataAccess;
using MockDataTransferObject;
using System.Data;
using System.Text.RegularExpressions;
using System.Collections.ObjectModel;

namespace MockBusiness
{
    public class UserBusiness
    {
        #region Initialize
        private static UserBusiness _instance;
        private readonly UserDataAccess _userDataAccess;
        private readonly RoleDataAccess _roleDataAccess;

        /// <summary>
        /// Gets the user data test.
        /// </summary>
        public Collection<User> UserDataTest
        {
            get
            {
                return _userDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Gets the role data test.
        /// </summary>
        public Collection<Role> RoleDataTest
        {
            get
            {
                return _roleDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="UserBusiness"/> class from being created.
        /// </summary>
        private UserBusiness()
        {
            _userDataAccess = new UserDataAccess();
            _roleDataAccess = new RoleDataAccess();
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="UserBusiness"/> class from being created.
        /// </summary>
        /// <param name="isFake">if set to <c>true</c> [is fake].</param>
        private UserBusiness(bool isFake)
        {
            _userDataAccess = new UserDataAccess(isFake);
            _roleDataAccess = new RoleDataAccess(isFake);
        }

        /// <summary>
        /// Retrieves the instance.
        /// </summary>
        /// <returns></returns>
        public static UserBusiness RetrieveInstance()
        {
            if (_instance == null)
                _instance = new UserBusiness();
            return _instance;
        }

        /// <summary>
        /// Retrieves the instance.
        /// </summary>
        /// <param name="isFake">if set to <c>true</c> [is fake].</param>
        /// <returns></returns>
        public static UserBusiness RetrieveInstance(bool isFake)
        {
            if (_instance == null)
                _instance = new UserBusiness(isFake);
            return _instance;
        }
        #endregion

        #region CUD
        /// <summary>
        /// Inserts the specified user.
        /// </summary>
        /// <param name="user">The user.</param>
        public void Insert(User user)
        {
            if (user == null)
            {
                throw new MockException("User is null", "Business");
            }
            if (_userDataAccess.Exist(user.UserId))
            {
                throw new MockException("UserId was existed", "Business");
            }
            if (_userDataAccess.IsExistUserName(user.UserName))
            {
                throw new MockException("Username was existed", "Business");
            }
            Role role = user.Role;
            if (role == null)
            {
                throw new MockException("Role is null", "Business");
            }
            if (!_roleDataAccess.Exist(role.RoleId))
            {
                throw new MockException("Role was not existed", "Business");
            }
            _userDataAccess.Create(user);
        }

        /// <summary>
        /// Updates the specified user.
        /// </summary>
        /// <param name="user">The user.</param>
        public void Update(User user)
        {
            if (user == null)
            {
                throw new MockException("User is null", "Business");
            }
            if (!_userDataAccess.Exist(user.UserId))
            {
                throw new MockException("UserId was existed", "Business");
            }
            Role role = user.Role;
            if (role == null)
            {
                throw new MockException("Role is null", "Business");
            }
            if (!_roleDataAccess.Exist(role.RoleId))
            {
                throw new MockException("Role was not existed", "Business");
            }
            _userDataAccess.Update(user);
        }

        /// <summary>
        /// Changes the password.
        /// </summary>
        /// <param name="user">The user.</param>
        public void ChangePassword(User user)
        {
            if (user == null)
            {
                throw new MockException("User is null", "Business");
            }
            if (!_userDataAccess.Exist(user.UserId))
            {
                throw new MockException("User was not existed", "Business");
            }
            _userDataAccess.Update(user);
        }

        /// <summary>
        /// Deletes the specified user id.
        /// </summary>
        /// <param name="userId">The user id.</param>
        public void Delete(string userId)
        {
            if (userId == null)
            {
                throw new MockException("User is null", "Business");
            }
            if (!_userDataAccess.Exist(userId))
            {
                throw new MockException("userId is not exist", "Business");
            }
            _userDataAccess.Delete(userId);
        }
        #endregion

        #region R
        /// <summary>
        /// Gets the by id.
        /// </summary>
        /// <param name="userId">The user id.</param>
        /// <returns></returns>
        public User GetById(object userId)
        {
            return _userDataAccess.GetById(userId);
        }

        /// <summary>
        /// Authenticates the user.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <param name="password">The password.</param>
        /// <returns></returns>
        public User AuthenticateUser(string userName, string password)
        {
            if (userName == null || password == null)
            {
                return null;
            }
            return _userDataAccess.GetByUserNameAndPassword(userName, password);
        }

        /// <summary>
        /// Gets the name of the by user.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        public User GetByUserName(string userName)
        {
            if (userName == null)
            {
                return null;
            }
            return _userDataAccess.GetByUserName(userName);
        }

        /// <summary>
        /// Determines whether [is active user name] [the specified user name].
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns>
        ///   <c>true</c> if [is active user name] [the specified user name]; otherwise, <c>false</c>.
        /// </returns>
        public bool IsActiveUserName(string userName)
        {
            if (userName == null)
            {
                return false;
            }
            return _userDataAccess.IsExistUserNameAndIsActive(userName, true);
        }

        /// <summary>
        /// Determines whether [is exist user name] [the specified user name].
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns>
        ///   <c>true</c> if [is exist user name] [the specified user name]; otherwise, <c>false</c>.
        /// </returns>
        public bool IsExistUserName(string userName)
        {
            return _userDataAccess.IsExistUserName(userName);
        }
        #endregion

        #region Other
        /// <summary>
        /// Generates the name of the user.
        /// </summary>
        /// <param name="firstName">The first name.</param>
        /// <param name="lastName">The last name.</param>
        /// <returns></returns>
        public string GenerateUserName(string firstName, string lastName)
        {
            lastName = lastName.Trim();
            string username = UserUtility.GenerateUserName(firstName, lastName);
            if (username == null)
            {
                return null;
            }
            if (lastName.IndexOf(" ", StringComparison.CurrentCulture) != -1)
            {
                return null;
            }
            string userTemp = username;
            int index = 1;
            while (_userDataAccess.IsExistUserName(userTemp))
            {
                userTemp = username + index.ToString(CultureInfo.InvariantCulture);
                index++;
            }
            return userTemp;
        }

        /// <summary>
        /// Formats the name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public static string FormatName(string name)
        {
            return Utility.StandString(name);
        }

        /// <summary>
        /// Generates the password.
        /// </summary>
        /// <returns></returns>
        public static string GeneratePassword()
        {
            return UserUtility.GeneratePassword(12);
        }

        /// <summary>
        /// Checks the valid email.
        /// </summary>
        /// <param name="email">The email.</param>
        /// <returns></returns>
        public static bool CheckValidEmail(string email)
        {
            if (email == null)
            {
                return false;
            }
            return Regex.IsMatch(email, @"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*");
        }
        #endregion
    }
}
